package com.gulimall.cart.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.gulimall.cart.feign.ProductFeignService;
import com.gulimall.cart.interceptor.CartUserInterceptor;
import com.gulimall.cart.service.CartService;
import com.gulimall.cart.to.UserInfoTo;
import com.gulimall.cart.vo.CartVo;
import com.gulimall.common.constrant.CartConstant;
import com.gulimall.common.to.SkuInfoTo;
import com.gulimall.common.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

import static java.awt.SystemColor.info;

/**
 * @author kkk
 * @date 2022/8/2
 */
@Service
@Slf4j
public class CartServiceImpl implements CartService {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private ProductFeignService productFeignService;
    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;

    @Override
    public CartVo.CartItemVo addProduct(Long skuId, Integer count) {
        BoundHashOperations<String, String, String> hashOperations = getHashOperations();

        CartVo.CartItemVo cartItemVo = null;
        String cartItemVoJson = hashOperations.get(skuId.toString());
        if (StringUtils.hasText(cartItemVoJson)) {
            cartItemVo = JSONObject.parseObject(cartItemVoJson, CartVo.CartItemVo.class);
            cartItemVo.setCount(cartItemVo.getCount() + count);
        } else {
            //根据skuId 调用远程服务获取商品信息
            cartItemVo = getProductInfo(skuId, count);
        }

        String cartItemJson = JSONObject.toJSONString(cartItemVo);
        if (StringUtils.hasText(cartItemJson)) {
            //获取redis操作hash对象
            hashOperations.put(skuId.toString(), cartItemJson);
        }

        return cartItemVo;
    }

    @Override
    public CartVo.CartItemVo getCartItem(Long skuId) {
        BoundHashOperations<String, String, String> hashOperations = getHashOperations();
        String cartItemJson = hashOperations.get(skuId.toString());
        return JSONObject.parseObject(cartItemJson, CartVo.CartItemVo.class);
    }

    @Override
    public CartVo getCartList() {
        UserInfoTo userInfoTo = CartUserInterceptor.toThreadLocal.get();
        StringBuilder key = new StringBuilder(CartConstant.USER_CART_PREFIX);
        Map<Long, CartVo.CartItemVo> tempCartVo =
                getCartVoByKey(CartConstant.USER_CART_PREFIX + userInfoTo.getUserKey());

        if (userInfoTo.getUserId() != null) {
            key.append(userInfoTo.getUserId());
            Map<Long, CartVo.CartItemVo> cartVoMap = getCartVoByKey(key.toString());

            //已经登录，将临时购物车数据合并到用户购物车中
            for (Map.Entry<Long, CartVo.CartItemVo> cartItemVoEntry : tempCartVo.entrySet()) {
                if (cartVoMap.containsKey(cartItemVoEntry.getKey())) {
                    CartVo.CartItemVo cartItemVo = cartVoMap.get(cartItemVoEntry.getKey());
                    CartVo.CartItemVo tempCart = tempCartVo.get(cartItemVoEntry.getKey());
                    cartItemVo.setCount(cartItemVo.getCount() + tempCart.getCount());
                } else {
                    cartVoMap.put(cartItemVoEntry.getKey(), cartItemVoEntry.getValue());
                }
            }

            //添加完后，删除临时购物车的数据
            Boolean delete = redisTemplate.delete(CartConstant.USER_CART_PREFIX + userInfoTo.getUserKey());

            CartVo cartVo = new CartVo();
            cartVo.setItems(cartVoMap.values().stream().map(item -> item).collect(Collectors.toList()));

            return cartVo;
        } else {
            CartVo cartVo = new CartVo();
            cartVo.setItems(tempCartVo.values().stream().map(item -> item).collect(Collectors.toList()));

            return cartVo;
        }
    }

    @Override
    public void changeItemCheck(Long skuId, boolean checked) {
        BoundHashOperations<String, String, String> hashOperations = getHashOperations();
        CartVo.CartItemVo cartItem = getCartItem(skuId);
        cartItem.setCheck(!checked);
        hashOperations.put(skuId.toString(), JSONObject.toJSONString(cartItem));
    }

    @Override
    public void changeItemCount(Long skuId, Integer count) {
        BoundHashOperations<String, String, String> hashOperations = getHashOperations();
        CartVo.CartItemVo cartItem = getCartItem(skuId);
        cartItem.setCount(count);
        hashOperations.put(skuId.toString(), JSONObject.toJSONString(cartItem));
    }

    @Override
    public void deleteItem(Long skuId) {
        BoundHashOperations<String, String, String> hashOperations = getHashOperations();
        hashOperations.delete(skuId.toString());
    }

    @Override
    public List<CartVo.CartItemVo> getCheckItem() {
        if (CartUserInterceptor.toThreadLocal.get() == null) {
            return null;
        } else {
            BoundHashOperations<String, String, String> hashOperations = getHashOperations();
            List<Long> skuIds = new ArrayList<>();
            List<CartVo.CartItemVo> cartItemList =
                    Objects.requireNonNull(hashOperations.values()).stream().map(item -> {
                        if (item == null) {
                            return null;
                        }
                        CartVo.CartItemVo cartItemVo = JSONObject.parseObject(item, CartVo.CartItemVo.class);
                        skuIds.add(cartItemVo.getSkuId());
                        return cartItemVo;
                    }).filter(Objects::nonNull).filter(CartVo.CartItemVo::isCheck).collect(Collectors.toList());

            if (skuIds.size() > 0) {
                R r = productFeignService.querySkuPrice(skuIds);
                if (r.getResult() == 0) {
                    Map<String, Double> pricesMap = (Map<String, Double>) r.get("pricesMap");
                    for (CartVo.CartItemVo cartItemVo : cartItemList) {
                        cartItemVo.setPrice(BigDecimal.valueOf(pricesMap.get(cartItemVo.getSkuId().toString())));
                    }
                }
            }

            return cartItemList;
        }
    }

    public Map<Long, CartVo.CartItemVo> getCartVoByKey(String key) {
        BoundHashOperations<String, String, String> hashOperations = redisTemplate.boundHashOps(key);
        Map<String, String> entries = hashOperations.entries();
        Map<Long, CartVo.CartItemVo> cartMap = new HashMap<>();

        for (Map.Entry<String, String> stringEntry : entries.entrySet()) {
            cartMap.put(Long.parseLong(stringEntry.getKey()), JSONObject.parseObject(stringEntry.getValue(),
                    CartVo.CartItemVo.class));
        }

        return cartMap;
    }

    public BoundHashOperations<String, String, String> getHashOperations() {
        UserInfoTo userInfoTo = CartUserInterceptor.toThreadLocal.get();
        StringBuilder key = new StringBuilder(CartConstant.USER_CART_PREFIX);
        if (userInfoTo.getUserId() != null) {
            key.append(userInfoTo.getUserId());
        } else {
            key.append(userInfoTo.getUserKey());
        }
        return redisTemplate.boundHashOps(key.toString());
    }

    private CartVo.CartItemVo getProductInfo(Long skuId, Integer count) {
        CartVo.CartItemVo cartItemVo = new CartVo.CartItemVo();

        CompletableFuture<Void> skuInfoFuture = CompletableFuture.runAsync(() -> {
            //1. 从其他服务获取商品信息
            R info = productFeignService.info(skuId);
            if (info.getResult() == 0) {
                SkuInfoTo skuInfo = JSONObject.parseObject(JSONObject.toJSONString(info.get("skuInfo")),
                        SkuInfoTo.class);
                cartItemVo.setCount(count);
                cartItemVo.setSkuId(skuId);
                cartItemVo.setCheck(true);
                cartItemVo.setImage(skuInfo.getSkuDefaultImg());
                cartItemVo.setPrice(skuInfo.getPrice());
                cartItemVo.setTitle(skuInfo.getSkuTitle());
            } else {
                log.error("远程调用product服务 info 错误 {} ", info.toString());
            }
        }, threadPoolExecutor);

        CompletableFuture<Void> skuAttrFuture = CompletableFuture.runAsync(() -> {
            //2. 从其他服务获取属性集合
            R skuAttr = productFeignService.getSkuAttr(skuId);
            if (skuAttr.getResult() == 0) {
                List<String> skuAttrs = JSONObject.parseObject(JSONObject.toJSONString(skuAttr.get("skuAttrs")),
                        List.class);
                cartItemVo.setSkuAttr(skuAttrs);
            } else {
                log.error("远程调用product服务 getSkuAttr 错误 {} ", info.toString());
            }
        }, threadPoolExecutor);

        CompletableFuture<Void> allOf = CompletableFuture.allOf(skuInfoFuture, skuAttrFuture);
        try {
            allOf.get();
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }

        return cartItemVo;
    }
}
